/** 通用事件集合 */
import Point from 'ol/geom/Point';
import { fromLonLat, transform } from 'ol/proj';
import * as turf from '@turf/turf'

const chartConfig = {
  EPSGCode: "EPSG:3857"
}

const pointLonToXy = (x, y) => {
  return new Point(fromLonLat([x, y]));
}

const pointLonLat = (x, y) => {
  return new Point([x, y]);
}

/**
 * 当前投影下坐标系转经纬度，并解决ol递增递减bug
 * @param {Array} coor 经纬度
 */
const getRealLonAndLat = (coor) => {
  let MapCoordinate = [...coor]
  const index = Math.floor((MapCoordinate[0] + 180) / 360)
  MapCoordinate[0] = MapCoordinate[0] - 360 * index
  return MapCoordinate
}

// 当前坐标系转经纬度
const transformNowToLonlat = (list) => {
  let MapCoordinate = transform(list, chartConfig.EPSGCode, 'EPSG:4326');
  return getRealLonAndLat(MapCoordinate)
}

/**
 * 经纬度转当前坐标系
 * @param {*} list [lon, lat]
 * @returns
 */
const transformLonlatToNow = (list) => {
  return transform(list, 'EPSG:4326', chartConfig.EPSGCode);
}

// to自己
const transformToMe = (list) => {
  return list
}

// 根据传入id删除海图中所有dom元素
const removeDomById = (id) => {
  var element = document.getElementById(id);
  if (element) element.parentNode.removeChild(element);
}

/**
 * 海图线处理
 * 将经过180度分割线的数据进行转换
 * @param [[lon, lat], [lon, lat]] list
 * 第一位是经度，第三位是坐标经度
 * @return [[lon, lat], [lon, lat]] 坐标点
 */
function transformLineForPoint(list, fn = transformToMe) {
  const length = list.length;
  let newList = []
  list[0].push(list[0][0])
  newList.push(fn([list[0][2], list[0][1]]))
  for (let index = 1; index < length; ++index) {
    const before = list[index - 1]
    const now = list[index]
    // 首先判断是否在同一面内
    const c = parseFloat(before[0]) - parseFloat(now[0])
    if (Math.abs(c) <= 180) {
      // c小于0，即向东
      let d = parseFloat(before[2]) - c
      list[index].push(d)
    } else {
      // c大于0，即向东
      let d = 0;
      if (c >= 0) {
        d = (360 + parseFloat(now[0]) - parseFloat(before[0])) + parseFloat(before[2])
      } else {
        d = parseFloat(before[2]) - (360 + parseFloat(before[0]) - parseFloat(now[0]))
      }
      list[index].push(d)
    }
    newList.push(fn([list[index][2], list[index][1]]))
  }
  return newList
}

/**
 * 根据x和y计算距离和夹角
 * @param {*} x 
 * @param {*} y 
 * @returns 
 */
function calculateDistanceAndAngle(x, y) {
  // 1. 计算与原点的距离
  const distance = Math.sqrt(x * x + y * y);
  // 2. 计算与y轴的夹角
  const angleFromXAxis = Math.atan2(Math.abs(x), y); // 与x轴的夹角（弧度）
  let angleFromYAxis = Math.abs(Math.PI / 2 - angleFromXAxis); // 与y轴的夹角（弧度）
  // 将弧度转换为角度
  angleFromYAxis = angleFromYAxis * (180 / Math.PI);
  // 返回计算结果
  const angle = 90 - angleFromYAxis
  return {
    distance: distance,
    angle: x >= 0 ? angle : -angle
  };
}

export function calculateDestination(lat0, lon0, bearing, distance) {
  const R = 6371000; // 地球半径，单位米
  const toRadians = Math.PI / 180; // 角度转弧度因子
  const toDegrees = 180 / Math.PI; // 弧度转角度因子

  // 将原点的经纬度转换为弧度
  lat0 = lat0 * toRadians;
  lon0 = lon0 * toRadians;

  // 将目标与正北的夹角转换为弧度
  bearing = bearing * toRadians;

  // 计算纬度的变化
  const deltaLat = distance / R * Math.cos(bearing);

  // 计算经度的变化
  const deltaLon = distance / (R * Math.cos(lat0)) * Math.sin(bearing);

  // 计算目标点的经纬度
  const lat1 = lat0 + deltaLat;
  const lon1 = lon0 + deltaLon;

  // 将结果转换回度数
  return {
    lat: lat1 * toDegrees,
    lon: lon1 * toDegrees
  };
}

/**
 * 根据两点，计算距离和方位
 * 1 是起点
 */
export function calculateDistanceAndAzimuth(startPoint, endPoint) {
  const start = turf.point(startPoint);
  const end = turf.point(endPoint);
  const distance = turf.distance(start, end);
  const bearing = turf.bearing(start, end);
  return {
    distance: distance * 1000, // 距离（单位：米）
    azimuth: (bearing + 360) % 360,   // 方位角（单位：度）
  };
}

/**
* 根据一个经纬度及距离角度，算出另外一个经纬度
* @param {*} lon 经度
* @param {*} lat 纬度
* @param {*} brng 方位角 ---- 正北方：000°或360° 正东方：090° 正南方：180° 正西方：270°
* @param {*} dist 90000距离(米)
*/
var mapNumberUtil = {
  rad: function rad(d) {
    return d * Math.PI / 180.0;
  },
  deg: function deg(d) {
    return d * 180 / Math.PI
  }
};
function getLonAndLat(lon, lat, brng, dist) {
  //大地坐标系资料WGS-84
  var a = 6378137; // 极坐标长半径
  var b = 6356752.3142; // 极坐标短半径
  var f = 1 / 298.257223563; // 扁率
  var lon1 = lon * 1;
  var lat1 = lat * 1;
  var s = dist;
  var alpha1 = mapNumberUtil.rad(brng);
  var sinAlpha1 = Math.sin(alpha1);
  var cosAlpha1 = Math.cos(alpha1);
  var tanU1 = (1 - f) * Math.tan(mapNumberUtil.rad(lat1));
  var cosU1 = 1 / Math.sqrt((1 + tanU1 * tanU1)),
    sinU1 = tanU1 * cosU1;
  var sigma1 = Math.atan2(tanU1, cosAlpha1);
  var sinAlpha = cosU1 * sinAlpha1;
  var cosSqAlpha = 1 - sinAlpha * sinAlpha;
  var uSq = cosSqAlpha * (a * a - b * b) / (b * b);
  var A = 1 + uSq / 16384 * (4096 + uSq * (- 768 + uSq * (320 - 175 * uSq)));
  var B = uSq / 1024 * (256 + uSq * (- 128 + uSq * (74 - 47 * uSq)));
  var sigma = s / (b * A),
    sigmaP = 2 * Math.PI;
  while (Math.abs(sigma - sigmaP) > 1e-12) {
    var cos2SigmaM = Math.cos(2 * sigma1 + sigma);
    var sinSigma = Math.sin(sigma);
    var cosSigma = Math.cos(sigma);
    var deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (- 1 + 2 * cos2SigmaM * cos2SigmaM) - B / 6 * cos2SigmaM * (- 3 + 4 * sinSigma * sinSigma) * (- 3 + 4 * cos2SigmaM * cos2SigmaM)));
    sigmaP = sigma;
    sigma = s / (b * A) + deltaSigma;
  }
  var tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1;
  var lat2 = Math.atan2(sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1, (1 - f) * Math.sqrt(sinAlpha * sinAlpha + tmp * tmp));
  var lambda = Math.atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1);
  var C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
  var L = lambda - (1 - C) * f * sinAlpha * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (- 1 + 2 * cos2SigmaM * cos2SigmaM)));
  // var revAz = Math.atan2(sinAlpha, -tmp); // final bearing
  var lonLatObj = {
    lon: lon1 + mapNumberUtil.deg(L),
    lat: mapNumberUtil.deg(lat2)
  }
  return lonLatObj;
}

/**
 * 计算船舶的艏向线
 * @param {} 
 */
export const CalculateCogLine = (row) => {
  const topCenter = 0.75
  const center = {
    lon: row.lon,
    lat: row.lat
  }
  const TopCenter = getLonAndLat(center.lon, center.lat, row.cog, topCenter * row.length)
  const TopTo = getLonAndLat(TopCenter.lon, TopCenter.lat, row.cog, 30)
  return [TopCenter, TopTo]
}

/**
 * 轮廓计算
 * @params {*}
 * longitude 经度
 * latitude 纬度
 * course 角度
 * width 宽度
 * length 长度
 * leftWidth 左舷宽度
 */
const shipInfo = {}
function CalculateContour(row = shipInfo) {
  if (!row.lon || !row.lat || !row.cog || !row.length || !row.width) {
    return []
  }
  const scale = {
    topCenter: 0.75,
    middleCenter: 0.69,
    bottomCenter: 0.58,
    centerTop: 0.1,
    centerBottom: 0.25
  }
  const center = {
    lon: row.lon,
    lat: row.lat
  }
  row.length = parseInt(row.length)
  row.width = parseInt(row.width)
  row.cog = parseInt(row.cog || "0")
  const TopCenter = getLonAndLat(center.lon, center.lat, row.cog, scale.topCenter * row.length)
  const MiddleCenter = getLonAndLat(center.lon, center.lat, row.cog, scale.middleCenter * row.length)
  const BottomCenter = getLonAndLat(center.lon, center.lat, row.cog, scale.bottomCenter * row.length)
  const CenterBottom = getLonAndLat(center.lon, center.lat, (row.cog + 180) % 360, scale.centerBottom * row.length)
  const MiddleRight = getLonAndLat(MiddleCenter.lon, MiddleCenter.lat, (row.cog + 90) % 360, 0.30 * row.width)
  const MiddleLeft = getLonAndLat(MiddleCenter.lon, MiddleCenter.lat, (row.cog + 270) % 360, 0.30 * row.width)
  const BottomRight = getLonAndLat(BottomCenter.lon, BottomCenter.lat, (row.cog + 90) % 360, 0.5 * row.width)
  const BottomLeft = getLonAndLat(BottomCenter.lon, BottomCenter.lat, (row.cog + 270) % 360, 0.5 * row.width)
  const RightBottom = getLonAndLat(CenterBottom.lon, CenterBottom.lat, (row.cog + 90) % 360, 0.4 * row.width)
  const LeftBottom = getLonAndLat(CenterBottom.lon, CenterBottom.lat, (row.cog + 270) % 360, 0.4 * row.width)
  const RightTop = getLonAndLat(RightBottom.lon, RightBottom.lat, (row.cog + 45) % 360, (0.1 * row.width) * Math.SQRT2)
  const LeftTop = getLonAndLat(LeftBottom.lon, LeftBottom.lat, (row.cog + 315) % 360, (0.1 * row.width) * Math.SQRT2)
  return [
    [TopCenter.lon, TopCenter.lat],
    [MiddleRight.lon, MiddleRight.lat],
    [BottomRight.lon, BottomRight.lat],
    [RightTop.lon, RightTop.lat],
    [RightBottom.lon, RightBottom.lat],
    [LeftBottom.lon, LeftBottom.lat],
    [LeftTop.lon, LeftTop.lat],
    [BottomLeft.lon, BottomLeft.lat],
    [MiddleLeft.lon, MiddleLeft.lat],
    [TopCenter.lon, TopCenter.lat],
  ]
}

/**
 * 真轮廓下选中框计算
 * @param {*} className
 */
const CalculateSelectProp = {
  length: "length",
  width: "width",
  heading: "cog",
  lon: "lon",
  lat: "lat",
}
function CalculateSelect(row = shipInfo, prop = CalculateSelectProp) {
  const toTop = 0.75; // 中心点到船头
  const spaceLength = 20 // 船和框的间隔
  const lineLength = 20 // 线条长度
  const center = {
    lon: row[prop.lon],
    lat: row[prop.lat],
  }
  row[prop.length] = parseInt(row[prop.length])
  row[prop.width] = parseInt(row[prop.width])
  row[prop.heading] = parseInt(row[prop.heading])
  const topCenter = getLonAndLat(center[prop.lon], center[prop.lat], row[prop.heading], (toTop * row[prop.length]) + spaceLength)
  const bottomCenter = getLonAndLat(topCenter[prop.lon], topCenter[prop.lat], (row[prop.heading] + 180), row[prop.length] + spaceLength * 2)
  // 右上角
  const rightTop = getLonAndLat(topCenter[prop.lon], topCenter[prop.lat], (row[prop.heading] + 270) % 360, (row[prop.width] / 2) * Math.SQRT2 + 20)
  const rightTop1 = getLonAndLat(rightTop[prop.lon], rightTop[prop.lat], (row[prop.heading] + 180) % 360, lineLength)
  const rightTop2 = getLonAndLat(rightTop[prop.lon], rightTop[prop.lat], (row[prop.heading] + 90) % 360, lineLength)
  const rightTopList = [
    transformLonlatToNow([rightTop1[prop.lon], rightTop1[prop.lat]]),
    transformLonlatToNow([rightTop[prop.lon], rightTop[prop.lat]]),
    transformLonlatToNow([rightTop2[prop.lon], rightTop2[prop.lat]]),
  ]
  // 左上角
  const leftTop = getLonAndLat(topCenter[prop.lon], topCenter[prop.lat], (row[prop.heading] + 90) % 360, (row[prop.width] / 2) * Math.SQRT2 + 20)
  const leftTop1 = getLonAndLat(leftTop[prop.lon], leftTop[prop.lat], (row[prop.heading] + 270) % 360, lineLength)
  const leftTop2 = getLonAndLat(leftTop[prop.lon], leftTop[prop.lat], (row[prop.heading] + 180) % 360, lineLength)
  const leftTopList = [
    transformLonlatToNow([leftTop1[prop.lon], leftTop1[prop.lat]]),
    transformLonlatToNow([leftTop[prop.lon], leftTop[prop.lat]]),
    transformLonlatToNow([leftTop2[prop.lon], leftTop2[prop.lat]]),
  ]
  // 左下角
  const leftBottom = getLonAndLat(bottomCenter[prop.lon], bottomCenter[prop.lat], (row[prop.heading] + 90) % 360, (row[prop.width] / 2) * Math.SQRT2 + 20)
  const leftBottom1 = getLonAndLat(leftBottom[prop.lon], leftBottom[prop.lat], (row[prop.heading] + 0) % 360, lineLength)
  const leftBottom2 = getLonAndLat(leftBottom[prop.lon], leftBottom[prop.lat], (row[prop.heading] + 270) % 360, lineLength)
  const leftBottomList = [
    transformLonlatToNow([leftBottom1[prop.lon], leftBottom1[prop.lat]]),
    transformLonlatToNow([leftBottom[prop.lon], leftBottom[prop.lat]]),
    transformLonlatToNow([leftBottom2[prop.lon], leftBottom2[prop.lat]]),
  ]
  // 右下角
  const rightBottom = getLonAndLat(bottomCenter[prop.lon], bottomCenter[prop.lat], (row[prop.heading] + 270) % 360, (row[prop.width] / 2) * Math.SQRT2 + 20)
  const rightBottom1 = getLonAndLat(rightBottom[prop.lon], rightBottom[prop.lat], (row[prop.heading] + 90) % 360, lineLength)
  const rightBottom2 = getLonAndLat(rightBottom[prop.lon], rightBottom[prop.lat], (row[prop.heading] + 0) % 360, lineLength)
  const rightBottomList = [
    transformLonlatToNow([rightBottom1[prop.lon], rightBottom1[prop.lat]]),
    transformLonlatToNow([rightBottom[prop.lon], rightBottom[prop.lat]]),
    transformLonlatToNow([rightBottom2[prop.lon], rightBottom2[prop.lat]]),
  ]
  const list = [
    rightTopList,
    leftTopList,
    leftBottomList,
    rightBottomList
  ]
  return list
}

// 根据传入class删除海图中所有dom元素
const removeDomByClassName = (className) => {
  var dom = document.getElementsByClassName(className);
  for (let i = dom.length - 1; i >= 0; --i) {
    if (dom[i] != null) dom[i].parentNode.removeChild(dom[i]);
  }
}

/**
 * 计算夹角
 * @param [B,A,C] list A为顶点坐标
 * @param a,b,c: [lon, lat]
 * @returns
 */
const CalculationAngle = (list) => {
  var point1 = turf.point(list[0]);
  var point2 = turf.point(list[1]);
  var bearing = turf.bearing(point1, point2);
  if (bearing < 0) bearing = 360 + bearing
  return bearing.toFixed(2)
}

/**
 * 移动到指定地点
 * @param row []lon, lat]
 */
const moveToCenterByLonAndLat = (row, map, zoom, duration = 1500) => {
  var to = transformLonlatToNow([row[0], row[1]]);
  var view = map.getView();
  // 设置地图等级
  if (!zoom) {
    zoom = view.getZoom()
  }
  view.animate({
    center: to,
    duration: duration,
    zoom: zoom
  });
}

/**
 * 计算图形中心点
 * @param list [[lon, lat], ...]
 */
const getCenterPoint = (list) => {
  const data = list.map(m => turf.point([m[0], m[1]]))
  var features = turf.featureCollection(data);
  var center = turf.center(features);
  return center.geometry.coordinates
}

/**
* 获取转换后单位的距离
* @param {Number} radius 以米为单位的距离
* @returns {Number} circleRadius 以投影的单位为单位的距离
*/
const getRadius = (radius, map) => {
  let metersPerUnit = map.getView().getProjection().getMetersPerUnit();
  let circleRadius = radius / metersPerUnit
  return circleRadius;
}

// 根据雷达和xy计算经纬度
export const getLonLatByXY = (x, y, type) => {
  const leida = {
    bei: {
      lon: 119.45206246145788,
      lat: 29.17467466774048,
      angle: 18 + 7,
    },
    nan: {
      lon: 119.45208554818058,
      lat: 29.17450635050248,
      angle: 201 + 5.5,
    }
  }
  const now = leida[type]
  const { angle, distance } = calculateDistanceAndAngle(x, y);
  const m = calculateDestination(now.lat, now.lon, now.angle + angle, distance);
  return {
    latitude: m.lat,
    longitude: m.lon,
  }
}

// 根据V计算速度
export function getSpeedByV(row) {
  return Math.abs(row.v / Math.cos(row.azimuth * Math.PI / 180)) * 3600 / 1852;
}

export {
  pointLonToXy,
  pointLonLat,
  transformToMe,
  transformLineForPoint,
  getLonAndLat,
  CalculateContour,
  CalculateSelect,
  calculateDistanceAndAngle,
  removeDomByClassName,
  transformNowToLonlat,
  transformLonlatToNow,
  CalculationAngle,
  moveToCenterByLonAndLat,
  getCenterPoint,
  removeDomById,
  getRadius,
  getRealLonAndLat,
}
